(* 
  CS520 Project
  Will Blair
  wdblair@bu.edu
*)

staload "generator.sats"
staload "container.sats"
staload "schedule.sats"

staload "prelude/SATS/pointer.sats"
staload "libc/SATS/pthread.sats"

staload "libats/SATS/parworkshop.sats"
staload "libats/DATS/parworkshop.dats"

(* Keep lists and strings dynamic for now *)
assume gen_list = List
assume gen_string = String

local
  var generators : container(generator_template) = new_container()
  viewdef generators_view = container(generator_template) @ generators
//  
  var generators_cnt : int = 0
  viewdef generators_cnt_view = int @ generators_cnt
//  
  var generators_ready : int = 0
  viewdef generators_ready_view = int @ generators_ready
in
  val gens_ptr = &generators
  val gens_view = view@(generators)
  val gens_lock = generator_lock_make{generators_view}(gens_view | (*none*) )
//  
  val gens_cnt = &generators_cnt
  val generators_cnt_view = view@(generators_cnt)
  val generators_cnt_guard = generator_guard_make{generators_cnt_view}(generators_cnt_view)
//  
  val gens_ready_ptr = &generators_ready
  val generators_ready_view = view@(generators_ready)
  val generators_ready_lock = generator_lock_make{generators_ready_view}( generators_ready_view | (* None *) )
  val generators_ready_cond = generator_cond_make{generators_ready_view}( (* None *) )
end

implement
generator_dispatch{l} (ws, gens) = 
  case+ gens of
  | list_cons(gen,tail) => let
    val _ = workshop_add_worker(ws)
    val () = workshop_insert_work(ws,gen)
    in 
      generator_dispatch(ws,tail)
    end
  | list_nil => ( (*Done*) )

implement
generator_resource{l} (ws, gen) =
  let
    var schedule : schedule(event)
    val () = generator_init(gen)
    val () = schedule_init(schedule)
    val () = generator_rendezvous()
    val () = generator_birth(gen, schedule)
    val () = schedule_run(schedule)
  in 0 end

implement 
generator_rendezvous () = 
  let
     val (pf_r | () ) = generator_lock_acquire(generators_ready_lock)
     prval (pf_c) = generator_guard_acquire(generators_cnt_guard)
     val () = !gens_ready_ptr := (!gens_ready_ptr) + 1
     val ready = !gens_ready_ptr
     val total = !gens_cnt
  in
  if ready = total then let
    (* At the Rendezvous *)
    val () = !gens_ready_ptr := 0
    val () = generator_cond_broadcast(generators_ready_cond)
    prval () = generator_guard_release(pf_c | generators_cnt_guard)
    val () = generator_lock_release(pf_r | generators_ready_lock)
    in end
  else let
    prval () = generator_guard_release(pf_c | generators_cnt_guard)
    val ( pf_r | () ) = generator_cond_wait(pf_r | generators_ready_cond, generators_ready_lock)
    val () = generator_lock_release(pf_r | generators_ready_lock)
    in end
  end